part of shop;

///基本用户信息
class UserPref {
  ///用户名，昵称
  String name = '';

  /// 手机号码，用户唯一标识
  String phone = '';

  ///头像图片 url
  String avatar = 'defaultAvatarUrl';

  ///id，校内用户为学号
  String id = '';

  ///简介信息，包括位置信息，详细介绍等,使用时注意检查
  UserDetail detail = UserDetail();

  ///该构造方法仅供测试用
  UserPref();

  UserPref.fromMap(Map<String, dynamic> map) {
    name = map["name"];
    phone = map["phone"];
    avatar = map["avatar"];
    id = map["id"];
    detail = UserDetail.fromMap(map["detail"]);
  }
  factory UserPref.fromJson(String jsonString) {
    Map<String, dynamic> jsonMap =
        json.decode(jsonString) as Map<String, dynamic>;
    return UserPref.fromMap(jsonMap);
  }

  bool get hasData => name != '' && phone != '';

  //该函数使该类可被json.encode序列化
  toJson() =>
      {"name": name, "phone": phone, "avatar": avatar, "detail": detail.toJson()};

  @override
  String toString() => toJson().toString();
}

class UserDetail {
  String fullName = '';
  String dormitory = 'unknown';
  List<int> published = [];
  String introduce = '';
  List like = [];
  UserDetail();
  UserDetail.fromMap(Map<String, dynamic> map) {
    fullName = map["full_name"];
    dormitory = map['dormitory'];
    published = map['published'];
    introduce = map['introduce'];
    like = map['like'];
  }
  toJson() => {
        "fullName": fullName,
        "dormitory": dormitory,
        "published": published,
        "introduce": introduce,
        "like": like
      };
  @override
  String toString() => toString().toString();
}



///用户操作类
class User {
  ///用户信息，使用前先检查
  UserPref info;

  ///`token`不能为空，为空时请执行`getLocalState()`
  String? token;

  ///网络请求基本参数，不变
  static final _baseOptions = BaseOptions(
    //服务器地址
    baseUrl: "http://192.168.0.103:8080",
    connectTimeout: 5000,
    sendTimeout: 3000,
  );

  Dio dio;

  ///储存单例
  static User? _cache;

  ///正常使用用这个
  factory User() => _cache ?? User._init();

  User._init() : info = UserPref(),dio = Dio(_baseOptions) {
    _cache = this;
    dio.interceptors.add(LogInterceptor());
    dio.interceptors.add(AuthInterCeptor());
  }

  ///* -1:状态未知,需要执行getLocalState()
  ///* 0:有token，有info，已登录,
  ///* 1：无token，有info，未登录,
  ///* 2：无token，无info，未注册
  ///* -2：有token，无info，出错
  int get statusCode {
    if (token == null) {
      return -1;
    } else {
      if (token != '') {
        return info.hasData ? 0 : -2;
      } else {
        return info.hasData ? 1 : 2;
      }
    }
  }

  ///获取本地数据，返回执行结果，也可通过statusCode函数获取,
  ///
  ///* 0: 有token，有info，已登录,
  ///* 1：无token，有info，未登录,
  ///* 2：无token，无info，未注册
  Future<int> getLocalState() async {
    SharedPreferences sPref = await SharedPreferences.getInstance();
    token = sPref.getString("token") ?? '';
    String? infoStr = sPref.getString("info");
    if (infoStr != null) {
      info = UserPref.fromJson(infoStr);
    } else {
      return 2;
    }
    return token == '' ? 1 : 0;
  }

  ///获取本地用户信息，**注意检查**
  Future<String> getLocalInfo() async {
    SharedPreferences sPref = await SharedPreferences.getInstance();
    String? infoStr = sPref.getString("info");
    return infoStr ?? "";
  }

  ///输入id和密码，id可为学号或手机号
  Future<String?> login({required String tel, required String password}) async {
    Map body = {"tel": tel, "password": password};
    // String body='{"phone":$tel,"password":"1233h467777"}';
    Response? res;
    try {
      res=await dio.post('/login', data: body);

    }on DioError catch(e){
      if (e.type == DioErrorType.connectTimeout) {
        return "无法连接至服务器";
      }
      return "出错了";
    }
    Map tokenMap = res.data as Map<String, dynamic>;
    infoGet().then((value) {
    //服务器返回类型为text时用这句
    //Map jMap = json.decode(res.data);
    //或者直接这样
    //Map jMap = res.data.runtimeType==String ? json.decode(res.data) : res.data as Map<String, dynamic>;
    Map infoMap = value as Map<String, dynamic>;
    if(infoMap["code"]!=0){
      return infoMap['msg'].toString();
    }
    token = tokenMap["token"]??'';
    if (token == '') {
      return "出大问题了";
    } else {
      info = UserPref.fromMap(infoMap["info"]!);
      updateLocal();
      return null;
    }});
  }

  ///返回所有用户信息，但不会更新本地数据
  Future<String> infoGet() async{
    Response res;
    try {
      res=await dio.post('/info');
    }on DioError catch(e){
      if (e.type == DioErrorType.connectTimeout) {
        return "无法连接至服务器";
      }
      return "出错了";
    }
    return res.data;
  }

  ///注册，上传所有用户信息，返回执行结果
  ///TODO 注册分多步，逻辑写在外面
  // Future<int> register(String password) async {
  //   //检查用户名和id是否合法
  //   if (info.name == '' || info.phone == '') {
  //     return -1;
  //   }
  //   Map body = info.toJson() as Map<String, dynamic>;
  //   body.addAll(<String, String>{"password": password});
  //   Response res = await dio.post("/user/register", data: body);
  //   //Map jMap = json.decode(res.data);
  //   Map jMap = res.data as Map<String, dynamic>;
  //   token = jMap["token"];
  //   if (token == null) {
  //     //根据msg判断失败原因，需要和后端协商，先象征性的写写
  //     switch (jMap["msg"]) {
  //       case "该用户已注册":
  //         return 1;
  //       default:
  //         return -1;
  //     }
  //   }
  //   return 0;
  // }

  ///只更新本地数据
  updateLocal() async {
    SharedPreferences sPref = await SharedPreferences.getInstance();
    sPref.setString("info", info.toJson());
    if (token != null) {
      sPref.setString("token", token!);
    }
  }

  ///更新全部数据,返回执行结果
  updateInfo() async {
    updateLocal();
    if (token == null) {
      return "Token cannot be null";
    }
    Response res = await dio.post("/user/update", data: info.toJson());
    Map jMap = res.data as Map<String, dynamic>;
    return jMap["msg"];
  }

  ///修改密码
  changePassword(String oldPassWord, String newPassWord) async {
    Response res = await dio
        .post("/user/update", data: {"old": oldPassWord, "new": newPassWord});
    Map jMap = res.data as Map<String, dynamic>;
    return jMap["msg"];
  }

  ///获取购物车商品
  Future<List<int>> getLiked() async {
    SharedPreferences uPref = await SharedPreferences.getInstance();
    var localLikedListString = uPref.getStringList("Liked");
    List<int> likedproduct_idlist = [];
    if (localLikedListString != null) {
      for (int i = 0; i < localLikedListString.length; i++) {
        likedproduct_idlist.add(json.decode(localLikedListString[i])["id"]);
      }
    }
    return likedproduct_idlist;
  }

  //向服务器更新购物车列表
  Future<String> updateLiked() async {
    getLiked().then((value) {
      for (int i = 0; i < value.length; i++) {
        info.detail.like.add(value[i]);
      }
    });
    Response res = await dio.post("/update", data: info.toJson());
    Map jMap = res.data as Map<String, dynamic>;
    return jMap["msg"];
  }

  ///向服务器更新用户已发布的商品
  Future<String> updatePublishedid(int id) async {
    User._cache?.getLocalInfo().then((value) async {
      Map infoMap = value as Map<String, dynamic>;
      Map detailMap = infoMap["detail"] as Map<String, dynamic>;
      var res = await dio.post("",data: detailMap["published"]);
      //注:目前detailMap["published"]是一个list
      Map jMap = res.data as Map<String, dynamic>;
      return jMap["msg"];
    }
    );
    return "";
  }

  ///向服务器请求用户已发布的商品
  Future<String> getPublishedid() async {
    var res = await dio.get("");
    Map jMap = res.data as Map<String, dynamic>;
    return jMap["msg"];
  }
}

//以下方法就是一些具体的操作了,是否归在该类还有待考虑
//把token附在请求头

///获取已发布商品
getPublished() {}
